package cn.springcloud.alibaba.security.handler;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.util.HtmlUtils;

import java.io.IOException;
import java.util.Map;

@Slf4j
@Component
public class MyWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator {

	/**
	 * UnsupportedGrantTypeException：不支持的授权类型异常
	 * InvalidGrantException：用户名或者密码错误的异常
	 */
	@Override
	public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
		log.error(e.getMessage(), e);
		ResponseEntity<OAuth2Exception> response = super.translate(e);
		OAuth2Exception oAuth2Exception = response.getBody();
		Assert.notNull(oAuth2Exception, "oAuth2Exception cannot be null");
		UserOAuth2Exception exception = new UserOAuth2Exception(oAuth2Exception.getMessage(), oAuth2Exception);
		return ResponseEntity.ok().body(exception);
	}

	@JsonSerialize(using = UserOAuth2ExceptionSerializer.class)
	private static class UserOAuth2Exception extends OAuth2Exception {

		public UserOAuth2Exception(String msg, Throwable t) {
			super(msg, t);
		}

		public String getOAuth2ErrorCode() {
			return "null";
		}

		public int getHttpErrorCode() {
			return 401;
		}
	}

	public static class UserOAuth2ExceptionSerializer extends StdSerializer<UserOAuth2Exception> {

		protected UserOAuth2ExceptionSerializer() {
			super(UserOAuth2Exception.class);
		}

		@Override
		public void serialize(UserOAuth2Exception e, JsonGenerator generator, SerializerProvider serializerProvider) throws IOException {
			generator.writeStartObject();
			generator.writeObjectField("code", e.getHttpErrorCode());
			String message = e.getMessage();
			if (message != null) {
				message = HtmlUtils.htmlEscape(message);
			}
			generator.writeStringField("message", message);
			if (e.getAdditionalInformation() != null) {
				for (Map.Entry<String, String> entry : e.getAdditionalInformation().entrySet()) {
					String key = entry.getKey();
					String add = entry.getValue();
					generator.writeStringField(key, add);
				}
			}
			generator.writeEndObject();
		}
	}
}
